﻿using System;
using System.Collections.Specialized;
using System.Linq;
using System.Web.Hosting;
using System.Web.Security;
using WebShop.Contracts;
using WebShop.DAL.Repositories;
using WebShop.Models;

namespace WebShop.Infrastructure.Providers
{
    public class WebShopRoleProvider : RoleProvider
    {
        private string _applicationName;

        public override string ApplicationName
        {
            get { return _applicationName; }
            set { _applicationName = value; }
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(name))
            {
                name = "MyRoleProvider";
            }
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "NW Role Provider");
            }

            base.Initialize(name, config);

            _applicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
        }

        private string GetConfigValue(string configValue, string defaultValue)
        {
            if (string.IsNullOrEmpty(configValue))
                return defaultValue;

            return configValue;
        }

        private ArgumentException CreateArgumentNullOrEmptyException(string paramName)
        {
            return new ArgumentException(string.Format("Argument cannot be null or empty: {0}", paramName));
        }

        #region override

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            /*using (NWDB context = new NWDB())
            {
                List<User> users = context.Users.Where(usr => usernames.Contains(usr.UserName)).ToList();
                List<Role> roles = context.Roles.Where(r => roleNames.Contains(r.RoleName)).ToList();
                foreach (User user_loopVariable in users)
                {
                    User user = user_loopVariable;
                    foreach (Role role_loopVariable in roles)
                    {
                        Role role = role_loopVariable;
                        if (!user.Roles.Contains(role))
                        {
                            user.Roles.Add(role);
                        }
                    }
                }
                int iiiii = context.SaveChanges();
            }*/
            using (var context = new NWDB())
            {
                foreach (string username in usernames)
                {
                    User user = context.Users.SingleOrDefault(x => x.UserName == username);
                    if (user != null)
                    {
                        foreach (string rolename in roleNames)
                        {
                            Role role = context.Roles.SingleOrDefault(x => x.RoleName == rolename);
                            if (role != null)
                            {
                                if (!user.Roles.Contains(role))
                                {
                                    user.Roles.Add(role);
                                }
                            }
                        }
                    }
                }
                context.SaveChanges();
            }
        }

        public override void CreateRole(string roleName)
        {
            if (string.IsNullOrEmpty(roleName))
            {
                throw CreateArgumentNullOrEmptyException("roleName");
            }
            using (var context = new NWDB())
            {
                dynamic role = context.Roles.FirstOrDefault(r => r.RoleName == roleName);
                if (role != null)
                {
                    throw new InvalidOperationException(string.Format("Role exists: {0}", roleName));
                }
                var newRole = new Role
                                  {
                                      RoleName = roleName
                                  };
                context.Roles.Add(newRole);
                context.SaveChanges();
            }
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            if (string.IsNullOrEmpty(roleName))
            {
                throw CreateArgumentNullOrEmptyException("roleName");
            }
            using (var context = new NWDB())
            {
                dynamic role = context.Roles.FirstOrDefault(r => r.RoleName == roleName);
                if (role == null)
                {
                    throw new InvalidOperationException("Role not found");
                }
                if (throwOnPopulatedRole)
                {
                    dynamic usersInRole = role.Users.Any;
                    if (usersInRole)
                    {
                        throw new InvalidOperationException(string.Format("Role populated: {0}", roleName));
                    }
                }
                else
                {
                    foreach (User user in role.Users)
                    {
                        User usr = user;
                        context.Users.Remove(usr);
                    }
                }
                context.Roles.Remove(role);
                context.SaveChanges();
                return true;
            }
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            if (string.IsNullOrEmpty(roleName))
            {
                throw CreateArgumentNullOrEmptyException("roleName");
            }
            if (string.IsNullOrEmpty(usernameToMatch))
            {
                throw CreateArgumentNullOrEmptyException("usernameToMatch");
            }
            using (var context = new NWDB())
            {
                IQueryable<string> query = from r in context.Roles from u in r.Users where r.RoleName == roleName && u.UserName.Contains(usernameToMatch) select u.UserName;
                return query.ToArray();
            }
        }

        public override string[] GetAllRoles()
        {
            using (var context = new NWDB())
            {
                return context.Roles.Select(r => r.RoleName).ToArray();
            }
        }

        public override string[] GetRolesForUser(string username)
        {
            if (string.IsNullOrEmpty(username))
            {
                throw CreateArgumentNullOrEmptyException("userName");
            }
            using (var context = new NWDB())
            {
                User user = context.Users.FirstOrDefault(usr => usr.UserName == username);
                if (user == null)
                {
                    throw new InvalidOperationException(string.Format("User not found: {0}", username));
                }
                return user.Roles.Select(r => r.RoleName).ToArray();
            }
        }

        public override string[] GetUsersInRole(string roleName)
        {
            if (string.IsNullOrEmpty(roleName))
            {
                throw CreateArgumentNullOrEmptyException("roleName");
            }
            using (var context = new NWDB())
            {
                Role role = context.Roles.FirstOrDefault(r => r.RoleName == roleName);
                if (role == null)
                {
                    throw new InvalidOperationException("Role not found");
                }
                return role.Users.Select(usr => usr.UserName).ToArray();
            }
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            if (string.IsNullOrEmpty(username))
            {
                throw CreateArgumentNullOrEmptyException("userName");
            }
            if (string.IsNullOrEmpty(roleName))
            {
                throw CreateArgumentNullOrEmptyException("roleName");
            }
            using (var context = new NWDB())
            {
                dynamic user = context.Users.FirstOrDefault(usr => usr.UserName == username);
                if (user == null)
                {
                    return false;
                }
                dynamic role = context.Roles.FirstOrDefault(r => r.RoleName == roleName);
                if (role == null)
                {
                    return false;
                }
                return user.Roles.Contains(role);
            }
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            using (var context = new NWDB())
            {
                foreach (string curUser in usernames)
                {
                    string username = curUser;
                    string us = username;
                    User user = context.Users.FirstOrDefault(u => u.UserName == us);
                    if (user != null)
                    {
                        foreach (string rolenameLoopVariable in roleNames)
                        {
                            string rolename = rolenameLoopVariable;
                            string rl = rolename;
                            Role role = user.Roles.FirstOrDefault(r => r.RoleName == rl);
                            if (role != null)
                            {
                                user.Roles.Remove(role);
                            }
                        }
                    }
                }
                context.SaveChanges();
            }
        }

        public override bool RoleExists(string roleName)
        {
            if (string.IsNullOrEmpty(roleName))
            {
                throw CreateArgumentNullOrEmptyException("roleName");
            }
            using (var context = new NWDB())
            {
                dynamic result = context.Roles.FirstOrDefault(r => r.RoleName == roleName);
                if (result != null)
                {
                    return true;
                }

                return false;
            }
        }

        #endregion
    }
}